/*
 * Player.java
 *
 * Created on 16. Dezember 2006, 18:35
 *
 * Copyright (c) 2007 Daniel Gronau
 *
 * This file is part of KanjiTori.
 *
 * KanjiTori is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * KanjiTori is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 */

package kanjitori;

import com.jme.bounding.BoundingBox;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.CameraNode;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;
import com.jme.system.DisplaySystem;
import java.util.List;
import kanjitori.events.AbstractListener;
import kanjitori.events.BotKilledEvent;
import kanjitori.events.ItemCollectedEvent;
import kanjitori.events.ManagerService;
import kanjitori.events.PlayerHurtEvent;
import kanjitori.events.PlayerRelocateEvent;
import kanjitori.graphics.Thing;
import kanjitori.graphics.bot.Bot;
import kanjitori.graphics.ortho.hud.AbstractHud;
import kanjitori.graphics.ortho.hud.Hud;
import kanjitori.graphics.item.Item;
import kanjitori.lesson.Entry;
import kanjitori.map.ContentMatrix;
import kanjitori.map.Position;
import kanjitori.util.Boom;
import kanjitori.util.GraphicUtil;


/**
 *
 * @author Pirx
 */
public class Player implements Thing {
    
    private static Player INSTANCE;

    private Node playerNode;
    private Node collisionNode;
    private CameraNode camNode;
    private Entry entry;
    private ContentMatrix contentMatrix;
    private int health = 100;
    private int teleporter = 0;
    private int defChange = 0;
    
    /** Creates a new instance of Player 
     * @param rootNode 
     * @param contentMatrix 
     * @param skyboxTextures 
     */
    public Player(Node rootNode, ContentMatrix contentMatrix, String[] skyboxTextures) {
        this.contentMatrix = contentMatrix;
        INSTANCE = this;
        DisplaySystem display = DisplaySystem.getDisplaySystem();
        Camera cam = display.getRenderer().getCamera();
        cam.setFrustumPerspective(50.0f, (float) display.getWidth() / (float) display.getHeight(), 0.25f, 500);
        camNode = new CameraNode("camera", cam);
        camNode.updateWorldData( 0 );

        playerNode = new Node();
        rootNode.attachChild(playerNode);
        
        Box collisionBox = new Box("pbox", new Vector3f(), 0.5f, 0.5f, 0.5f);
        collisionBox.setCullMode(Box.CULL_ALWAYS);
        collisionBox.setModelBound(new BoundingBox());
        collisionBox.updateModelBound();
        collisionNode = new Node("collisionNode");
        collisionNode.attachChild(collisionBox);
                
        playerNode.attachChild(GraphicUtil.getSkybox(skyboxTextures));
        playerNode.attachChild(camNode);
        playerNode.attachChild(collisionNode);
        
        Boom.setExplosion(playerNode, new ColorRGBA(0.5f, 0.3f, 0.3f, 0.8f), new ColorRGBA(1f, 0f, 0f, 0.4f), 15f, 20f, 50f, 80);
        
        relocate();
        AbstractHud.getHud().showHealth(health);
        AbstractHud.getHud().showTeleporters(teleporter);
        AbstractHud.getHud().showChange(defChange);
        
        ManagerService.register(new AbstractListener<ItemCollectedEvent>(ItemCollectedEvent.class){
            public void notify(ItemCollectedEvent event) {
                itemCollected(event.getContent());
            }
        });
        ManagerService.register(new AbstractListener<PlayerHurtEvent>(PlayerHurtEvent.class){
            public void notify(PlayerHurtEvent event) {
                playerHurt(event.getContent());
            }
        });
        ManagerService.register(new AbstractListener<BotKilledEvent>(BotKilledEvent.class){
            public void notify(BotKilledEvent event) {
                botKilled();
            }
        });
    }
    
    public Entry getEntry() {
        return entry;
    }
    
    public void setEntry(Entry entry) {
        this.entry = entry;
        Hud hud = AbstractHud.getHud();
        if (hud != null) {
            hud.showDefinition(entry.getKey());
        }
    }
    
    public CameraNode getCamNode() {
        return camNode;
    }
    
    public Node getCollisionNode() {
        return collisionNode;
    }
    
    private void relocate() {
       Position freePos = contentMatrix.findFreePos();
       Vector3f position = new Vector3f(freePos.x()*2, 0, freePos.y()*2);
       playerNode.setLocalTranslation(position);
       playerNode.updateWorldVectors();
       playerNode.updateRenderState();
       ManagerService.fireEvent(new PlayerRelocateEvent(this));
       Boom.explode(playerNode);
    }
    
    public void itemCollected(Item item) {
        switch (item.getType()) {
            case HEALTH : changeHealth(5); break;
            case TELEPORT: changeTeleporters(1); break;
            case DEF_CHANGE: changeDef(1); break;
        }
    }

    public void useItem(Item.Type type) {
        switch (type) {
                        case TELEPORT: 
                if (teleporter > 0) {
                    changeTeleporters(-1); 
                    relocate();
                }    
                break;
            case DEF_CHANGE: 
                if (defChange > 0) {
                    if (entry.isDirty()) {
                        break;
                    }
                    Entry newEntry = entry;
                    List<Entry> activeEntries = LevelManager.getActiveEntries();
                    if (activeEntries.size() == 1) {
                        break;
                    }
                    changeDef(-1); 
                    while(newEntry.equals(entry)) {
                       newEntry = activeEntries.get(LevelManager.RANDOM.nextInt(activeEntries.size()));
                    }
                    entry = newEntry;
                    AbstractHud.getHud().showDefinition(entry.getKey());
                }    
                break;
        }
    }    
    
    public void changeTeleporters(int amount) {
        teleporter += amount;
        if (teleporter > 3) {
            teleporter = 3;
        }
        if (teleporter < 0) {
            teleporter = 0;
        }
        AbstractHud.getHud().showTeleporters(teleporter);
    }
    
    public void changeDef(int amount) {
        defChange += amount;
        if (defChange > 3) {
            defChange = 3;
        }
        if (defChange < 0) {
            defChange = 0;
        }
        AbstractHud.getHud().showChange(defChange);
    }    
    
    public void changeHealth(int amount) {
        health += amount;
        if (health > 100) {
            health = 100;
        }
        if (health < 0) {
            LevelManager.die();
        } 
        AbstractHud.getHud().showHealth(health);
    }
    
    private void playerHurt(Bot bot) {
        changeHealth(-15);
        if (health >= 0) {
           relocate();
        }
    }
    
    private void botKilled() {
        changeHealth(2);
    }
    
    public void entrySolved() {
        setEntry(LevelManager.getNextEntry());
    }
    
    public static Player getPlayer() {
        return INSTANCE;
    }

    public Node getNode() {
        return playerNode;
    }

    public boolean checkPlayerCollision() {
        return false;
    }
    
}
